//@ts-ignore

import {stack_jd} from './stack'
import { LITERAL, IDENTIFIER, GROUPING_BEGIN_JD, GROUPING_BEGIN, GROUPING_END, INFIX_OP, PREFIX_OP, Tokenizer}  from './Tokenizer'
import {Parse_jd}  from './Parser'
/**
 * 使用两个stack来实现表达式的计算，参考源码：https://zhuanlan.zhihu.com/p/60609567
 */
export function tokenizeCacluate(expr:string, jsonObj:any):any{
    console.log("hello")
    let i=0;
    let meal = expr.trim();
    let stackOperator = new stack_jd();
    let stackNum = new stack_jd();
    Parse_jd.createPrecendenceHash();

    console.log('#############Tokenizer function tokenize begin################################################################');

    //扫描字符串
    mainloop:
        while ((meal != '') && (i<99)) {
            meal = meal.trimLeft();
            console.log('==========loop %d times=========>', i);
            console.log('parser meal:', meal);
            i++
            for (let j=0; j<Tokenizer.regExes.length; j++) {
                let singleRegEx = Tokenizer.regExes[j];
                let re = singleRegEx[2];
                if (re.test(meal)) {
                    let result = re. exec(meal);
                    let wholeMatch = result[0];
                    let tokenValue = result[0];

                    //TOdo 此处摘抄，不懂意思
                    let eat = wholeMatch.length;
                    if (result[2]) {
                        eat -= result[2].length;
                    }

                    meal = meal.substr(eat);

                    // If a translation function is defined, run it
                    if (singleRegEx[3]) {
                        tokenValue = singleRegEx[3](tokenValue);
                    }


                    //扫描meal，若为变量或者数字，直接入数栈
                    if(Tokenizer.isVarible(singleRegEx[0])){
                        //arr[0] 为类型
                        //arr[1] 为字符串
                        //arr[2] 为具体的值
                        stackNum.stackPush(singleRegEx[0], singleRegEx[1], tokenValue)
                        continue mainloop
                    }

                    //扫描meal，若为&[,直接入符号栈
                    if(Tokenizer.isGroupBegin(singleRegEx[0])) {
                        stackOperator.stackPush(singleRegEx[0], singleRegEx[1], tokenValue)
                        continue mainloop;
                    }

                    if(Tokenizer.isOperator(singleRegEx[0])){
                        //如果运算符号栈不为空
                        //字符串循环比较
                        while(!stackOperator.stack_is_empty()){
                            let topStackOperator = stackOperator.stack_top()
                            //如果运算符栈顶优先级高，则进行计算，否则在else中入栈
                            let priStackOperator =  Parse_jd.getPrecedence(topStackOperator.type, topStackOperator.value);
                            let priMealOperator = Parse_jd.getPrecedence(singleRegEx[0],tokenValue);
                            //此处加上=，主要是方便例如处理4-3-2+1这种情况，这种情况就优先处理4-3，避免压两次‘-’到栈。保证同优先级从做到右进行计算
                            if( priStackOperator >= priMealOperator ){
                                //此处应该考虑不断的循环看粘贴和arr【0】比较
                                //弹出两个操作数进行计算,此处仅仅考虑了二元运算符
                                let operator = stackOperator.stack_pop()
                                let operator_symbol = operator.value;

                                if(operator_symbol === '+' || operator_symbol === '-' || operator_symbol === '*' || operator_symbol === '/'){
                                    //此处按照道理应该进行取值运算等
                                    //弹出两个操作数进行计算,此处仅仅考虑了二元运算符
                                    let operator_num2 = stackNum.stack_pop()
                                    let operator_num2_value = operator_num2.value;

                                    let operator_num1 = stackNum.stack_pop()
                                    let operator_num1_value = operator_num1.value;

                                    let newNum = Parse_jd.optionMap[operator_symbol](operator_num1_value, operator_num2_value)
                                    stackNum.stackPush(operator_num1.type, operator_num1.symbol, newNum)
                                    continue;
                                }

                                if(operator_symbol === '=='){
                                    let operator_num2 = stackNum.stack_pop()
                                    let operator_num2_value = operator_num2.value;

                                    let operator_num1 = stackNum.stack_pop()
                                    let operator_num1_value = operator_num1.value;

                                    let newNum = Parse_jd.optionMap[operator_symbol](operator_num1_value, operator_num2_value)
                                    stackNum.stackPush(operator_num1.type, operator_num1.symbol, newNum)
                                    continue;
                                }

                                if(operator_symbol === '!='){
                                    let operator_num2 = stackNum.stack_pop()
                                    let operator_num2_value = operator_num2.value;

                                    let operator_num1 = stackNum.stack_pop()
                                    let operator_num1_value = operator_num1.value;

                                    let newNum = Parse_jd.optionMap[operator_symbol](operator_num1_value, operator_num2_value)
                                    stackNum.stackPush(operator_num1.type, operator_num1.symbol, newNum)
                                    continue;
                                }

                                if(operator_symbol === '?'){
                                    let operator_num2 = stackNum.stack_pop()
                                    let operator_num2_value = operator_num2.value;

                                    let operator_num1 = stackNum.stack_pop()
                                    let operator_num1_value = operator_num1.value;
                                }
                            }else{
                                //栈顶运算符号优先级低符号压栈
                                stackOperator.stackPush(singleRegEx[0], singleRegEx[1], tokenValue)
                                continue mainloop;
                            }
                        }
                        stackOperator.stackPush(singleRegEx[0], singleRegEx[1], tokenValue)
                        continue mainloop;
                    }

                    //处理末尾符号问题 }
                    if(Tokenizer.isGroupEnd(singleRegEx[0])){
                        let tempTokens = [];
                        while(!stackOperator.stack_is_empty()){
                          let topStackOperator = stackOperator.stack_pop()
                          if(!Tokenizer.isPair(topStackOperator.value, tokenValue)){
                              let operator_symbol = topStackOperator.value;
                              //先考虑加减乘除，后续再考虑扩展的事
                              //二元运算符
                              if(operator_symbol === '+' || operator_symbol === '-' || operator_symbol === '*' || operator_symbol === '/'){
                                  //此处按照道理应该进行取值运算等
                                  //弹出两个操作数进行计算,此处仅仅考虑了二元运算符
                                  let operator_num2 = stackNum.stack_pop()
                                  let operator_num2_value = operator_num2.value;

                                  let operator_num1 = stackNum.stack_pop()
                                  let operator_num1_value = operator_num1.value;

                                  let newNum = Parse_jd.optionMap[operator_symbol](operator_num1_value, operator_num2_value)
                                  stackNum.stackPush(operator_num1.type, operator_num1.symbol, newNum)
                                  continue;
                              }

                              if(operator_symbol === ','){
                                  let operator_num2 = stackNum.stack_pop()
                                  let operator_num2_value = operator_num2.value;

                                  let operator_num1 = stackNum.stack_pop()
                                  let operator_num1_value = operator_num1.value;
                                  tempTokens.push(operator_num2_value);
                                  tempTokens.push(operator_num1_value);
                              }


                              //这里需要么？
                              if(operator_symbol == '$calc('){
                                  let operator_num = stackNum.stack_pop()
                                  let operator_num_value = operator_num.value;
                                  let result = Parse_jd.optionMap[operator_symbol](operator_num_value)
                                  stackNum.stackPush(LITERAL, 'literal_number', result)
                                  console.log('parser result:', result);
                                  continue;
                              }


                              //Todo 是否可以删除掉，既然父判断的if条件中有是否Group的判断
                              if(operator_symbol == 'ceil('){
                                  let operator_num = stackNum.stack_pop()
                                  let operator_num_value = operator_num.value;
                                  let result = Parse_jd.optionMap[operator_symbol](operator_num_value)
                                  stackNum.stackPush(LITERAL, 'literal_number', result)
                                  console.log('parser result:', result);
                                  continue;
                              }
                              
                              if(operator_symbol == ':'){
                                  let operator_symbol = stackOperator.stack_top()
                                  let operator_symbol_value = operator_symbol.value;
                                  if(operator_symbol_value === "?"){
                                      stackOperator.stack_pop();
                                      let operator_num2 = stackNum.stack_pop()
                                      let operator_num2_value = operator_num2.value;

                                      let operator_num1 = stackNum.stack_pop()
                                      let operator_num1_value = operator_num1.value;

                                      let operator_num0 = stackNum.stack_pop()
                                      let operator_num0_value = operator_num0.value;

                                      if(operator_num0_value == true){
                                          stackNum.stackPush(operator_num1.type, operator_num1.symbol, operator_num1_value)
                                      }else{
                                          stackNum.stackPush(operator_num2.type, operator_num2.symbol, operator_num2_value)
                                      }
                                  }
                                  continue;
                              }

                              //TODO一元运算符

                              //TODO三元运算符
                          }else{
                              //增加代码，若是${需要增加取值操作， 还有@等
                              let operator_symbol = topStackOperator.value;

                              if(operator_symbol == '${'){
                                  //here working
                                  let operator_num = stackNum.stack_pop()
                                  let operator_num_value = operator_num.value;
                                  //let result = eval(prefix+'.'+operator_num_value);
                                  let result =evalReplace(operator_num_value, jsonObj)
                                  stackNum.stackPush(LITERAL, 'literal_string_double_quotes', result)
                                  console.log('parser result:', result);
                              }

                              if(operator_symbol == '@{'){
                                  //TODO
                                  let operator_num = stackNum.stack_pop()
                                  let operator_num_value = operator_num.value;
                                  stackNum.stackPush(LITERAL, 'literal_string_double_quotes', operator_num_value)
                                  console.log('parser result:', result);
                              }

                              if(operator_symbol == '$calc('){
                                  let operator_num = stackNum.stack_pop()
                                  let operator_num_value = operator_num.value;
                                  let result = Parse_jd.optionMap[operator_symbol](operator_num_value)
                                  stackNum.stackPush(LITERAL, 'literal_number', result)
                                  console.log('parser result:', result);
                              }

                              if(operator_symbol == 'ceil('){
                                  let operator_num = stackNum.stack_pop()
                                  let operator_num_value = operator_num.value;
                                  let result = Parse_jd.optionMap[operator_symbol](operator_num_value)
                                  stackNum.stackPush(LITERAL, 'literal_number', result)
                                  console.log('parser result:', result);
                              }

                              if(operator_symbol == "$joint("){
                                  let temp = tempTokens.reverse().join('');
                                  stackNum.stackPush(LITERAL, 'literal_string_string_quotes', temp)
                                  continue;
                              }

                              continue mainloop;
                          }
                        }
                    }

                    //若为普通符号
                    //扫描meal，若为一元或二元符号,此处假设为二元符号

                    continue mainloop;
                }
            }
        }

        //字符串扫描完
    while(!stackOperator.stack_is_empty()){
        let operator = stackOperator.stack_pop()
        let operator_symbol = operator.value;

        //二元运算符
        if(operator_symbol == '+' || operator_symbol == '-' || operator_symbol == '*' || operator_symbol == '/'){

            let operator_symbol = operator.value;

            let operator_num2 = stackNum.stack_pop()
            let operator_num2_value = operator_num2.value;

            let operator_num1 = stackNum.stack_pop()
            let operator_num1_value = operator_num1.value;

            let newNum = Parse_jd.optionMap[operator_symbol](operator_num1_value, operator_num2_value)
            stackNum.stackPush(operator_num1.type, operator_num1.symbol, newNum)
            continue;
        }


        if(operator_symbol == ':'){
            let operator_symbol = stackOperator.stack_top()
            let operator_symbol_value = operator_symbol.value;
            if(operator_symbol_value === "?"){
                stackOperator.stack_pop();
                let operator_num2 = stackNum.stack_pop()
                let operator_num2_value = operator_num2.value;

                let operator_num1 = stackNum.stack_pop()
                let operator_num1_value = operator_num1.value;

                let operator_num0 = stackNum.stack_pop()
                let operator_num0_value = operator_num0.value;

                if(operator_num0_value == true){
                    stackNum.stackPush(operator_num1.type, operator_num1.symbol, operator_num1_value)
                }else{
                    stackNum.stackPush(operator_num2.type, operator_num2.symbol, operator_num2_value)
                }
            }
            continue;
        }
    }

    console.log('#############Tokenizer function tokenize end################################################################');
    console.log("")
    console.log("")
    console.log("")
    console.log('stackNum result=========begin==============>');
    //stackNum.stack_print();
    stackNum.stack_print_all()
    let node = stackNum.stack_pop()
    let calcResult = node?.value
    console.log('stackNum result=========end================>')
    console.log("result is "+calcResult)
    console.log("")
    console.log("")
    console.log("")
    //stackNum.stack_print();
    //stackOperator.stack_print();
    return calcResult;
    //Parser.createPrecendenceHash();
}

function evalReplace(expr:string, jsonObj:any){
    let arr:string[]=expr.split(/\[|\]|\./).filter(item=>item!="");

    let result = arr.reduce((res, cur)=>{
        try{
            if( res && res[cur]){
                return res[cur]
            }else{
                return undefined;
            }
        }catch (e){
            console.log('eval get error')
        }
    }, jsonObj)

    console.log('result----', result)
    return result;
}
